package br.edu.unifei.cct720.alieninvasion.entity;

import java.awt.Graphics;

import br.edu.unifei.cct720.alieninvasion.collisions.BoundingBox;
import br.edu.unifei.cct720.alieninvasion.main.gui.GameCanvas;
import br.edu.unifei.cct720.alieninvasion.resources.Sprite;
import br.edu.unifei.cct720.alieninvasion.resources.SpriteStore;

/**
 * Class that represents an game entity.
 * 
 * An entity represents any element that appears in the game. The
 * entity is responsible for resolving collisions and movement
 * based on a set of properties defined either by subclass or externally.
 * 
 * @author Felipe Knappe
 */
public abstract class Entity {
	
	/**
	 * The current x-coordinate of this entity
	 */ 
	protected double x;
	
	/**
	 * The current y-coordinate of this entity
	 */
	protected double y;
	
	/**
	 * The sprite that represents this entity
	 */
	protected Sprite sprite;
	
	/**
	 * The canvas in which the entity exists
	 */
	protected GameCanvas game;
	
	/**
	 * The current speed of this entity horizontally (pixels/sec)
	 */
	protected double dx;
	
	/**
	 * The current speed of this entity vertically (pixels/sec)
	 */
	protected double dy;
	
	/**
	 * The rectangle used for this entity during collisions resolution
	 */
	private BoundingBox me;
	
	/**
	 * The rectangle used for other entities during collision resolution
	 */
	private BoundingBox him;
	
	/**
	 * Class Constructor
	 * Create an entity based on a sprite image and a location.
	 * 
	 * @param ref The reference to the image to be displayed for this entity
 	 * @param x The initial x location of this entity
	 * @param y The initial y location of this entity
	 */
	public Entity(GameCanvas g, String ref,int x,int y) {
		this.game = g;
		this.sprite = SpriteStore.get().getSprite(ref);
		this.x = x;
		this.y = y;
		this.dx = 0.0;
		this.dy = 0.0;
		this.me = new BoundingBox();
		this.him = new BoundingBox();
	}
	
	/**
	 * Method responsible for request that this entity move
	 * itself based on time elapsed.
	 * 
	 * @param delta The shift value
	 * 
	 */
	public void move(long delta) {
		// update the location of the entity based on move speeds
		x += (delta * this.dx) / 1000;
		y += (delta * this.dy) / 1000;
	}
	
	/**
	 * Method responsible for set the horizontal velocity of this entity
	 * 
	 * @param dx The horizontal speed of this entity (pixels/sec)
	 */
	public void setHorizontalMovement(double dx) {
		this.dx = dx;
	}

	/**
	 * Method responsible for set the vertical velocity of this entity
	 * 
	 * @param dy The vertical speed of this entity (pixels/sec)
	 */
	public void setVerticalMovement(double dy) {
		this.dy = dy;
	}
	
	/**
	 * Method responsible for retrieve the horizontal velocity of this entity.
	 * 
	 * @return double
	 */
	public double getHorizontalMovement() {
		return dx;
	}

	/**
	 * Method responsible for retrieve the vertical velocity of this entity
	 * 
	 * @return double
	 */
	public double getVerticalMovement() {
		return dy;
	}
	
	/**
	 * Method responsible for draw this entity to the 
	 * graphics context provided
	 * 
	 * @param g The graphics context on which to draw
	 */
	public void draw(Graphics g) {
		sprite.draw(g,(int) x,(int) y);
	}
	
	/**
	 * Method responsible for the logic associated with 
	 * this entity. 
	 * 	 
	 */
	public void doLogic() {}
	
	/**
	 * Method resposnbile for retrieve the x-coordinate 
     * of this entity.
	 * 
	 * @return int
	 */
	public int getX() {
		return (int) x;
	}

	/**
	 * Method resposnbile for retrieve the y-coordinate 
     * of this entity.
	 * 
	 * @return int
	 */
	public int getY() {
		return (int) y;
	}
	
	/**
	 * Method responsible for check this entity has collided
	 * with other. 
	 * 
	 * @param other The other entity to check collision against
	 * 
	 * @return boolean
	 */
	public boolean collidesWith(Entity other) {
		me.setBounds((int) x, (int) y, sprite.getWidth(), sprite.getHeight());
		him.setBounds((int) other.x, (int) other.y, other.sprite.getWidth(), other.sprite.getHeight());

		return me.intersects(him);
	}
	
	/**
	 * Method responsible for notify this entity that it has collided 
	 * with another entity.
	 * 
	 * @param other The other collided entity
	 * 
	 */
	public abstract void collidedWith(Entity other);
}